#!/bin/bash

##################################################################
# Script Name: xservice
# Description: This script demonstrates how to use multi-line comments
#              in a Bash script. It includes various methods for
#              creating visually prominent comments.
# Author: Xiaokang Lv
# Date: 2024-07-20
##################################################################

# ================================================================
# Global
# ================================================================

VERSION="1.0.0"
RELEASE_DATE="2024-07-26"
AUTHOR="Xiaokang Lv"
EMAIL_ADDRESS="lv_xiaokang@buaa.edu.cn"

# Define color codes
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
MAGENTA='\033[0;35m'
CYAN='\033[0;36m'
WHITE='\033[0;37m'
BOLD='\033[1m'
NC='\033[0m' # No Color

if [ -n "$SUDO_USER" ]; then
    ORIGINAL_USER="$SUDO_USER"
else
    ORIGINAL_USER="$USER"
fi

# ================================================================
# Function
# ================================================================

# 检查依赖ROS节点是否运行
check_dependencies() {
    local nodes=("$@")
    if [ ${#nodes[@]} -eq 0 ]; then
        return 0
    fi

    for node in "${nodes[@]}"; do
        source /opt/ros/noetic/setup.bash && rosnode ping -c 1 "$node" > /dev/null 2>&1
        if [ $? -ne 0 ]; then
            echo "Not satisfied with dependency ${node}"
            return 1
        fi
    done
    return 0
}

# # 检查依赖ROS节点是否运行
# check_dependencies() {
#     local nodes=("$@")  # Store all arguments (node names) in an array.
#     if [ ${#nodes[@]} -eq 0 ]; then
#         return 0  # If no nodes are provided, return success.
#     fi

#     for node in "${nodes[@]}"; do
#         if [[ "$node" == "rosout" ]]; then
#             # Special case for "rosout": use pgrep to check if the process exists.
#             pgrep -x "rosout" > /dev/null 2>&1
#             if [ $? -ne 0 ]; then
#                 echo "Not satisfied with dependency ${node}"  # Print error if rosout is not running.
#                 return 1  # Return failure.
#             fi
#         else
#             # General case for other nodes: use rosnode ping.
#             source /opt/ros/noetic/setup.bash && rosnode ping -c 1 "$node" > /dev/null 2>&1
#             if [ $? -ne 0 ]; then
#                 echo "Not satisfied with dependency ${node}"  # Print error if node is unreachable.
#                 return 1  # Return failure.
#             fi
#         fi
#     done
#     return 0  # Return success if all nodes are reachable.
# }

# 查找服务文件
find_service_files() {
    local group="$1"
    local name="$2"

    if [[ -n "$group" && -n "$name" ]]; then
        local file="/etc/systemd/system/xs${group}_${name}.service"
        [[ -f "$file" ]] && echo "$file"
    elif [[ -n "$group" && -z "$name" ]]; then
        ls /etc/systemd/system/xs${group}_*.service 2>/dev/null
    elif [[ -z "$group" && -z "$name" ]]; then
        ls /etc/systemd/system/xs*_*.service 2>/dev/null
    fi
}

# 打印服务文件并询问用户确认删除
confirm_deletion() {
    local files=("$@")

    if [[ ${#files[@]} -eq 0 ]]; then
        echo "No service files found to delete."
        exit 0
    fi

    echo "The following service files will be deleted:"
    echo ""
    for file in "${files[@]}"; do
        echo -e "${RED}$file${NC}"
    done
    echo ""

    read -p "Do you want to continue and delete these files? (y/n) " confirm
    [[ "$confirm" != "y" && "$confirm" != "Y" ]] && { echo "Aborted."; exit 0; }
}

# 停止并禁用开机自启服务
stop_and_disable_services() {
    local files=("$@")

    for file in "${files[@]}"; do
        local service_name=$(basename "$file" .service)
        echo "Stopping and disabling service: $service_name"
        sudo systemctl stop "$service_name"
        sudo systemctl disable "$service_name"
    done
}

# 删除指定的服务文件
delete_service_files() {
    local files=("$@")

    for file in "${files[@]}"; do
        echo "Deleting service file: $file"
        sudo rm "$file" || { echo "Failed to delete $file"; exit 1; }
    done
}

# 获取服务状态对应的颜色代码
get_service_status_color() {
    local service_name="$1"
    local color_code="\e[0m" # 默认颜色
    
    # 检查是否开机自启
    if systemctl is-enabled --quiet "$service_name"; then
        color_code="\e[34m" # 蓝色
    fi

    # 检查服务是否正在运行
    if systemctl is-active --quiet "$service_name"; then
        color_code="\e[32m" # 绿色
    fi

    echo "$color_code"
}

# 打印服务的基本信息
print_service_info() {
    local file="$1"
    local service_name=$(basename "$file" .service)
    
    local is_enabled
    if systemctl is-enabled --quiet "$service_name"; then
        is_enabled="Yes"
    else
        is_enabled="No"
    fi

    local is_active
    if systemctl is-active --quiet "$service_name"; then
        is_active="Yes"
    else
        is_active="No"
    fi
    
    echo "Service Path: $file"
    echo "Group: $(basename "$file" | cut -d'_' -f1 | sed 's/xs//')"
    echo "Name: $(echo "$service_name" | sed 's/xs[0-9]*_//')"
    echo "Enabled: $is_enabled"
    echo "Active: $is_active"
    echo "----------------------------------------"
}

# 打印服务文件内容
print_service_file() {
    local file="$1"
    local service_name=$(basename "$file" .service)
    local color_code
    
    # 打印服务基本信息
    print_service_info "$file"
    
    # 获取服务状态对应的颜色代码
    color_code=$(get_service_status_color "$service_name")

    # 打印服务文件内容
    echo -e "${color_code}$(cat "$file")\e[0m"
    echo "========================================"  # 分隔符
}

get_pane_id() {
    local group="$1"
    local search_name="$2"
    
    export TMUX=/tmp/tmux-xservice/default
    local output=$(tmux list-panes -t "xservice$group:0" -F '#{pane_index}:#{pane_start_command}')
    
    while IFS= read -r line; do
        local pane_id="${line%%:*}"
        local start_command="${line#*:}"
        
        if [[ "$start_command" == *"PANE_NAME='$search_name'"* ]]; then
            echo "${pane_id//%}"
            return
        fi
    done <<< "$output"
    
    echo "-1"
}


# ================================================================
# --wait
# ================================================================

handle_wait() {
    local nodes=("$@")
    
    echo "Waiting for dependencies to be satisfied: ${nodes[@]}"

    while true; do
        if check_dependencies "${nodes[@]}"; then
            echo "All dependencies are satisfied."
            break
        fi
        echo "Waiting for dependencies..."
        sleep 0.6
    done
}

# ================================================================
# --run
# ================================================================

handle_run() {
    if [ $# -lt 3 ] || [ $# -gt 4 ]; then
        echo "Usage: xservice --run [group] [name] [command] [dependent_nodes (optional)]"
        exit 1
    fi

    local group="$1"
    local name="$2"
    local command="$3"
    shift 3
    local dependent_nodes=("$@")

    local session_name="xservice$group"
    mkdir -p /tmp/tmux-xservice
    export TMUX=/tmp/tmux-xservice/default

    if ! tmux has-session -t $session_name 2>/dev/null; then
        echo "Session $session_name does not exist. Creating a new session."
        tmux new-session -d -s $session_name "bash"
        
        # Wait until the session is created successfully
        while ! tmux has-session -t $session_name 2>/dev/null; do
            sleep 1
        done
        echo "Session $session_name created."
    fi

    echo "Session $session_name exists."
    tmux split-window -v -t $session_name "export PANE_NAME='$name';xservice --wait $dependent_nodes;$command;bash"
    echo "Adding a new pane and running '$command'."

    tmux select-layout -t $session_name tiled
    echo -e "To connect to the tmux session, use the command: \n\n${BLUE}tmux attach -t ${session_name}${NC}\n"
}


# ================================================================
# --create
# ================================================================

handle_create() {
    if [ $# -lt 3 ] || [ $# -gt 4 ]; then
        echo "Usage: sudo xservice --create [group] [name] [command] [dependent_nodes (optional)]"
        exit 1
    fi

    local group="$1"
    local name="$2"
    local command="$3"
    shift 3
    local dependent_nodes=("$@")

    local service_file="/etc/systemd/system/xs${group}_${name}.service"

    echo "Creating service file at $service_file"

    {
        echo "[Unit]"
        echo "Description=XService ${name}"
        echo "After=network.target"
        echo
        echo "[Service]"
        echo "Type=forking"
        echo "User=$ORIGINAL_USER"
        if [ -z "$dependent_nodes" ]; then
            echo "ExecStart=xservice --run $group $name '$command'"
        else
            echo "ExecStart=xservice --run $group $name '$command' '$dependent_nodes'"
        fi
        echo
        echo "[Install]"
        echo "WantedBy=multi-user.target"
    } > "$service_file"

    if [ $? -eq 0 ]; then
        echo "Reloading systemd daemon"
        sudo systemctl daemon-reload
    else
        echo "Failed to create service file"
        exit 1
    fi
}

# ================================================================
# --create_after_services
# ================================================================

handle_create_after_services() {
    if [ $# -lt 3 ] || [ $# -gt 4 ]; then
        echo "Usage: sudo xservice --create_after_services [group] [name] [command] [dependent_services (optional)]"
        exit 1
    fi

    local group="$1"
    local name="$2"
    local command="$3"
    shift 3
    local dependent_services=("$@")

    local service_file="/etc/systemd/system/xs${group}_${name}.service"

    echo "Creating service file at $service_file"

    {
        echo "[Unit]"
        echo "Description=XService ${name}"
        if [ -z "$dependent_services" ]; then
            echo "After=network.target"
        else
            echo "After=$dependent_services"
        fi
        echo 
        echo "[Service]"
        echo "Type=forking"
        echo "User=$ORIGINAL_USER"
        echo "ExecStart=xservice --run $group $name '$command'"
        echo
        echo "[Install]"
        echo "WantedBy=multi-user.target"
    } > "$service_file"

    if [ $? -eq 0 ]; then
        echo "Reloading systemd daemon"
        sudo systemctl daemon-reload
    else
        echo "Failed to create service file"
        exit 1
    fi
}

# ================================================================
# --delete
# ================================================================

handle_delete() {
    if [[ $# -gt 2 ]]; then
        echo "Usage: sudo xservice --delete [group (optional)] [name (optional)]"
        exit 1
    fi

    local group="$1"
    local name="$2"

    local service_files=($(find_service_files "$group" "$name"))
    if [[ ${#service_files[@]} -eq 0 ]]; then
        echo "No service files found to delete."
        exit 0
    fi

    confirm_deletion "${service_files[@]}"
    stop_and_disable_services "${service_files[@]}"
    delete_service_files "${service_files[@]}"

    echo "Reloading systemd daemon"
    sudo systemctl daemon-reload
}

# ================================================================
# --list
# ================================================================

handle_list() {
    if [[ $# -gt 2 ]]; then
        echo "Usage: xservice --list [group (optional)] [name (optional)]"
        exit 1
    fi

    local group="$1"
    local name="$2"

    local service_files=($(find_service_files "$group" "$name"))
    if [[ ${#service_files[@]} -eq 0 ]]; then
        echo "No service files found to list."
        exit 0
    fi

    echo "========================================"
    for file in "${service_files[@]}"; do
        print_service_file "$file"
    done
}

# ================================================================
# --edit
# ================================================================

handle_edit() {
    if [ "$#" -lt 2 ]; then
        echo "Usage: sudo xservice --edit [group] [name] [editor (optional, default is nano)]"
        return 1
    fi

    local group="$1"
    local name="$2"
    local editor="${3:-nano}"

    local service_files=($(find_service_files "$group" "$name"))
    if [[ ${#service_files[@]} -eq 0 ]]; then
        echo "No service files found to edit."
        exit 0
    fi

    case "$editor" in
        vim)
            echo "You are using vim. To save and exit:"
            echo "1. Press Esc to enter command mode."
            echo "2. Type :wq and press Enter to save and exit."
            echo "3. Alternatively, type :q! and press Enter to quit without saving."
            ;;
        nano)
            echo "You are using nano. To save and exit:"
            echo "1. Press Ctrl + O to write out (save) the file, then press Enter."
            echo "2. Press Ctrl + X to exit nano."
            ;;
        *)
            ;;
    esac

    sudo "$editor" "$service_files"

    echo "Reloading systemd daemon"
    sudo systemctl daemon-reload
}

# ================================================================
# --start
# ================================================================

handle_start() {
    if [[ $# -gt 2 ]]; then
        echo "Usage: sudo xservice --start [group (optional)] [name (optional)]"
        exit 1
    fi

    local group="$1"
    local name="$2"

    local service_files=($(find_service_files "$group" "$name"))
    if [[ ${#service_files[@]} -eq 0 ]]; then
        echo "No target services found to start."
        exit 0
    fi

    for file in "${service_files[@]}"; do
        local service_name=$(basename "$file" .service)
        echo "Starting service: $service_name"
        sudo systemctl start "$service_name"
    done

    echo "Start command processing completed."
}

# ================================================================
# --restart
# ================================================================

handle_restart() {
    if [[ $# -gt 2 ]]; then
        echo "Usage: sudo xservice --restart [group (optional)] [name (optional)]"
        exit 1
    fi

    local group="$1"
    local name="$2"

    local service_files=($(find_service_files "$group" "$name"))
    if [[ ${#service_files[@]} -eq 0 ]]; then
        echo "No target services found to restart."
        exit 0
    fi

    export TMUX=/tmp/tmux-xservice/default

    if [[ -n "$group" && -n "$name" ]]; then
        local pane_id=$(get_pane_id $group $name)
        if [ "$pane_id" -lt 0 ]; then
            echo "Pane $name not found in xservice$group"
            exit 0
        else
            echo "Stopping service in pane xservice$group.$pane_id"
            # 发送 Ctrl+C 信号
            tmux send-keys -t "xservice$group.$pane_id" C-c
            sleep 0.6  # 等待进程处理信号
            # 关闭 pane
            tmux kill-pane -t "xservice$group.$pane_id"
        fi
    elif [[ -n "$group" && -z "$name" ]]; then
        echo "Stopping all services in session xservice$group"
        # 发送 Ctrl+C 信号到所有 panes
        tmux list-panes -t "xservice$group" -F '#{pane_id}' | while read pane_id; do
            tmux send-keys -t "xservice$group.$pane_id" C-c
            sleep 0.6  # 等待进程处理信号
        done
        # 关闭整个 session
        tmux kill-session -t "xservice$group"
    elif [[ -z "$group" && -z "$name" ]]; then
        echo "Stopping all xservice sessions"
        # 发送 Ctrl+C 信号到所有 panes 在所有 sessions
        tmux list-sessions -F '#{session_name}' | grep '^xservice' | while read session_name; do
            tmux list-panes -t "$session_name" -F '#{pane_id}' | while read pane_id; do
                tmux send-keys -t "$session_name.$pane_id" C-c
                sleep 0.6  # 等待进程处理信号
            done
            # 关闭 session
            tmux kill-session -t "$session_name"
        done
    fi

    echo "Stop command processing completed."
    sleep 1

    for file in "${service_files[@]}"; do
        local service_name=$(basename "$file" .service)
        echo "Starting service: $service_name"
        sudo systemctl restart "$service_name"
    done

    echo "Start command processing completed."
}

# ================================================================
# --stop
# ================================================================

handle_stop() {
    if [[ $# -gt 2 ]]; then
        echo "Usage: sudo xservice --stop [group (optional)] [name (optional)]"
        exit 1
    fi

    local group="$1"
    local name="$2"

    export TMUX=/tmp/tmux-xservice/default

    if [[ -n "$group" && -n "$name" ]]; then
        local pane_id=$(get_pane_id $group $name)
        if [ "$pane_id" -lt 0 ]; then
            echo "Pane $name not found in xservice$group"
            exit 0
        else
            echo "Stopping service in pane xservice$group.$pane_id"
            # 发送 Ctrl+C 信号
            tmux send-keys -t "xservice$group.$pane_id" C-c
            sleep 0.6  # 等待进程处理信号
            # 关闭 pane
            tmux kill-pane -t "xservice$group.$pane_id"
        fi
    elif [[ -n "$group" && -z "$name" ]]; then
        echo "Stopping all services in session xservice$group"
        # 发送 Ctrl+C 信号到所有 panes
        tmux list-panes -t "xservice$group" -F '#{pane_id}' | while read pane_id; do
            tmux send-keys -t "xservice$group.$pane_id" C-c
            sleep 0.6  # 等待进程处理信号
        done
        # 关闭整个 session
        tmux kill-session -t "xservice$group"
    elif [[ -z "$group" && -z "$name" ]]; then
        echo "Stopping all xservice sessions"
        # 发送 Ctrl+C 信号到所有 panes 在所有 sessions
        tmux list-sessions -F '#{session_name}' | grep '^xservice' | while read session_name; do
            tmux list-panes -t "$session_name" -F '#{pane_id}' | while read pane_id; do
                tmux send-keys -t "$session_name.$pane_id" C-c
                sleep 0.6  # 等待进程处理信号
            done
            # 关闭 session
            tmux kill-session -t "$session_name"
        done
    fi

    echo "Stop command processing completed."
}

# ================================================================
# --enable
# ================================================================

handle_enable() {
    if [[ $# -gt 2 ]]; then
        echo "Usage: sudo xservice --enable [group (optional)] [name (optional)]"
        exit 1
    fi

    local group="$1"
    local name="$2"

    local service_files=($(find_service_files "$group" "$name"))
    if [[ ${#service_files[@]} -eq 0 ]]; then
        echo "No target services found to enable."
        exit 0
    fi

    for file in "${service_files[@]}"; do
        local service_name=$(basename "$file" .service)
        echo "Enable service: $service_name"
        sudo systemctl enable "$service_name"
    done

    echo "Enable command processing completed."
}

# ================================================================
# --disable
# ================================================================

handle_disable() {
    if [[ $# -gt 2 ]]; then
        echo "Usage: sudo xservice --disable [group (optional)] [name (optional)]"
        exit 1
    fi

    local group="$1"
    local name="$2"

    local service_files=($(find_service_files "$group" "$name"))
    if [[ ${#service_files[@]} -eq 0 ]]; then
        echo "No target services found to disable."
        exit 0
    fi

    for file in "${service_files[@]}"; do
        local service_name=$(basename "$file" .service)
        echo "Disable service: $service_name"
        sudo systemctl disable "$service_name"
    done

    echo "Disable command processing completed."
}

# ================================================================
# --status
# ================================================================

handle_status() {
    if [[ $# -gt 2 ]]; then
        echo "Usage: sudo xservice --status [group (optional)] [name (optional)]"
        exit 1
    fi

    local group="$1"
    local name="$2"

    local service_files=($(find_service_files "$group" "$name"))
    if [[ ${#service_files[@]} -eq 0 ]]; then
        echo "No target services found."
        exit 0
    fi

    echo "========================================"
    echo 
    for file in "${service_files[@]}"; do
        local service_name=$(basename "$file" .service)
        systemctl status "$service_name" --no-pager
        echo 
        echo "========================================"
        echo 
    done
}

# ================================================================
# --attach
# ================================================================

handle_attach() {
    if [[ $# -gt 1 ]]; then
        echo "Usage: sudo xservice --attach [group]"
        exit 1
    fi

    local group="$1"
    local session_name="xservice$group"

    export TMUX=/tmp/tmux-xservice/default
    tmux attach -t $session_name
}

# ================================================================
# main
# ================================================================

check_tmux_installed() {
    if ! command -v tmux &> /dev/null
    then
        echo -e "tmux is not installed. Install it with: \n\n${RED}sudo apt-get install tmux${NC}\n"
        exit 1
    fi
}

declare -A SHORT_OPTS
SHORT_OPTS=(
    ["-h"]="--help"
    ["-R"]="--run"
    ["-w"]="--wait"
    ["-c"]="--create"
    ["-cs"]="--create_after_services"
    ["-d"]="--delete"
    ["-l"]="--list"
    ["-e"]="--edit"
    ["-s"]="--start"
    ["-r"]="--restart"
    ["-t"]="--stop"
    ["-E"]="--enable"
    ["-D"]="--disable"
    ["-S"]="--status"
    ["-a"]="--attach"
)

print_help() {
    echo "xservice v$VERSION ($RELEASE_DATE)"
    echo "Author: $AUTHOR"
    echo "Email: $EMAIL_ADDRESS"
    echo
    echo "Usage: xservice [COMMAND] [OPTIONS]"
    echo
    echo "Commands:"
    echo "  --help, -h          Help"
    echo "  --create, -c        Create xservice"
    echo "  --create_after_services, -cs Create xservice after service"
    echo "  --delete, -d        Delete xservice (stop and disable in advance)"
    echo "  --list, -l          List the service file contents of xservice"
    echo "  --edit, -e          Edit the service file of xservice"
    echo "  --start, -s         Start xservice"
    echo "  --restart, -r       Restart xservice"
    echo "  --stop, -t          Stop xservice"
    echo "  --enable, -E        Enable xservice to start automatically at boot"
    echo "  --disable, -D       Disable xservice from starting automatically at boot"
    echo "  --status, -S        Display the current status of xservice"
    echo "  --attach, -a        Attach the current terminal to xservice"
    echo
    echo "Use 'xservice --help [COMMAND]' for more information about a command."
}

# 打印具体命令的帮助信息
print_command_help() {
    case "$1" in
        # --run|-r)
        #     echo "Usage: xservice --run [GROUP_ID] [CMD] [DEPENDENT_NODES(Optional)]"
        #     echo "Example 1: xservice --run 2 \"source /opt/ros/noetic/setup.bash && roscore\""
        #     echo "Example 2: xservice --run 2 \"source /AAA/devel/setup.bash && roslaunch BBB CCC.launch DDD:=EEE\" \"rosout FFF GGG/HHH\""
        #     ;;
        *)
            echo "Unknown command: $1"
            print_help
            exit 1
            ;;
    esac
}

process_command() {
    local command="$1"
    shift

    case "$command" in
        --run) handle_run "$@" ;;
        --wait) handle_wait "$@" ;;
        --create) handle_create "$@" ;;
        --create_after_services) handle_create_after_services "$@" ;;
        --delete) handle_delete "$@" ;;
        --list) handle_list "$@" ;;
        --edit) handle_edit "$@" ;;
        --start) handle_start "$@" ;;
        --restart) handle_restart "$@" ;;
        --stop) handle_stop "$@" ;;
        --enable) handle_enable "$@" ;;
        --disable) handle_disable "$@" ;;
        --status) handle_status "$@" ;;
        --attach) handle_attach "$@" ;;
        *)
            echo "Unknown command: $command"
            print_help
            exit 1
            ;;
    esac
}

main() {
    check_tmux_installed

    if [[ $# -eq 0 ]]; then
        print_help
        exit 0
    fi

    local command="$1"
    shift

    if [[ -n "${SHORT_OPTS[$command]}" ]]; then
        command="${SHORT_OPTS[$command]}"
    fi

    if [[ "$command" == "--help" ]]; then
        if [[ $# -gt 0 ]]; then
            print_command_help "$1"
        else
            print_help
        fi
        exit 0
    fi
    
    # source /opt/ros/noetic/setup.bash

    process_command "$command" "$@"
}

main "$@"
